#include "DXUT.h"
#include "TextureRenderer.h"
#include "SDKmisc.h"
#include <algorithm>

namespace
{
	/*const */DXGI_FORMAT textureFormat = DXGI_FORMAT_R16G16B16A16_UNORM;
	struct TEXVERTEX
	{
		D3DXVECTOR3 pos;
		D3DXVECTOR2 tex;
	};

	struct TEXCOLOR
	{
		typedef unsigned short Type;
		Type r, g, b, a;
		
		TEXCOLOR()
			:r(0), g(0), b(0), a(0)
		{}

		TEXCOLOR(Type r, Type g, Type b, Type a)
			:r(r), g(g), b(b), a(a)
		{}

		static TEXCOLOR getResColor(const TEXCOLOR& src, const TEXCOLOR& dst)
		{
			return 	TEXCOLOR(
				max(src.r, dst.r),
				max(src.g, dst.g),
				max(src.b, dst.b),
				max(src.a, dst.a));
		}
	};

	struct TEXNORM
	{
		typedef unsigned char Type;
		Type x, y, b, a;

		TEXNORM()
			:x(0), y(0)
		{}

		TEXNORM(Type x, Type y)
			:x(x), y(y)
		{}


		static TEXNORM getResColor(const TEXNORM& src, const TEXNORM& dst)
		{
			return 	TEXNORM(
				(float)src.x/3.f + dst.x,
				(float)src.y/3.f + dst.y);
		}
	};

	struct TexSlicesData
	{
		TexSlicesData()
			:texSliceMSAA(0), texSliceMSAARTV(0), texSliceMSAASRV(0), 
			texSlice(0), texSliceRTV(0), texSliceSRV(0)
		{}
		~TexSlicesData() { release(); }
		void release()
		{
			SAFE_RELEASE(texSliceMSAA);
			SAFE_RELEASE(texSliceMSAARTV);
			SAFE_RELEASE(texSliceMSAASRV);

			SAFE_RELEASE(texSlice);
			SAFE_RELEASE(texSliceRTV);
			SAFE_RELEASE(texSliceSRV);
			
			for(std::vector<ID3D11Texture2D*>::iterator it = texSlices.begin();
				it != texSlices.end(); ++it)
				SAFE_RELEASE(*it);
			texSlices.clear();
		}

		ID3D11Texture2D* texSliceMSAA;
		ID3D11RenderTargetView* texSliceMSAARTV;
		ID3D11ShaderResourceView* texSliceMSAASRV;

		ID3D11Texture2D* texSlice;
		ID3D11RenderTargetView* texSliceRTV;
		ID3D11ShaderResourceView* texSliceSRV;

		std::vector<ID3D11Texture2D*> texSlices;
	};

	enum VTUsage
	{
		vtCPUUsage = 0,
		vtGenerateMipMaps,
	};

	HRESULT	createVolumeTexture(UINT width, UINT height, UINT depth, VTUsage usage, ID3D11Texture3D* &tex)
	{
		ID3D11Device* pd3dDevice = DXUTGetD3D11Device();

		D3D11_TEXTURE3D_DESC texDesc;
		texDesc.Width   = width;
		texDesc.Height  = height;
		texDesc.Depth   = depth;
		texDesc.MipLevels = 0;
		texDesc.Format  = textureFormat;

		switch (usage)
		{
		case vtCPUUsage:
			texDesc.Usage           = D3D11_USAGE_STAGING;
			texDesc.BindFlags       = 0;
			texDesc.CPUAccessFlags	= D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; 
			texDesc.MiscFlags       = 0;
			break;

		case vtGenerateMipMaps:
			texDesc.Usage           = D3D11_USAGE_DEFAULT;
			texDesc.BindFlags       = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
			texDesc.CPUAccessFlags	= 0; 
			texDesc.MiscFlags       = D3D11_RESOURCE_MISC_GENERATE_MIPS;
		}

		return pd3dDevice->CreateTexture3D(&texDesc, 0, &tex);
	}

	HRESULT	createTextureSlices(UINT width, UINT height, UINT count, TexSlicesData& slicesData)
	{
		ID3D11Device* pd3dDevice = DXUTGetD3D11Device();

		HRESULT hr;

		DXGI_SAMPLE_DESC samplDesc;
		UINT maxQualityLevel = 0;
		samplDesc.Count = 8;
		pd3dDevice->CheckMultisampleQualityLevels(textureFormat, samplDesc.Count, &maxQualityLevel);
		samplDesc.Quality = maxQualityLevel - 1;

		D3D11_TEXTURE2D_DESC texDesc;
		texDesc.Width = width;
		texDesc.Height = height;
		texDesc.MipLevels = 1;
		texDesc.Format = textureFormat;
		texDesc.Usage = D3D11_USAGE_DEFAULT;
		texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
		texDesc.CPUAccessFlags = 0; 
		texDesc.MiscFlags = 0;
		texDesc.SampleDesc = samplDesc;
		texDesc.ArraySize = 1;

		V_RETURN(pd3dDevice->CreateTexture2D(&texDesc, 0, &slicesData.texSliceMSAA));
		V_RETURN(pd3dDevice->CreateRenderTargetView(slicesData.texSliceMSAA, 0, &slicesData.texSliceMSAARTV));
		V_RETURN(pd3dDevice->CreateShaderResourceView(slicesData.texSliceMSAA, 0, &slicesData.texSliceMSAASRV));

		texDesc.SampleDesc.Count = 1;
		texDesc.SampleDesc.Quality = 0;
		V_RETURN(pd3dDevice->CreateTexture2D(&texDesc, 0, &slicesData.texSlice));
		V_RETURN(pd3dDevice->CreateRenderTargetView(slicesData.texSlice, 0, &slicesData.texSliceRTV));
		V_RETURN(pd3dDevice->CreateShaderResourceView(slicesData.texSlice, 0, &slicesData.texSliceSRV));

		slicesData.texSlices.resize(count, 0);
		texDesc.Usage = D3D11_USAGE_STAGING;
		texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
		texDesc.BindFlags = 0;
		for (UINT i = 0; i < count; ++i)
			V_RETURN(pd3dDevice->CreateTexture2D(&texDesc, 0, &slicesData.texSlices[i]));

		return S_OK;
	}

	inline void getUVW(UINT i, UINT j, UINT k, ViewDirType vdt, 
		UINT width3d, UINT height3d, UINT depth3d, UINT &u, UINT &v, UINT &w)
	{
		switch (vdt)
		{
		case vdX:
			u = k;
			v = i;
			w = depth3d - j - 1;
			break;
		case vdY:
			u = j;
			v = height3d - k - 1;
			w = i;
			break;
		case vdZ:
			u = j;
			v = i;
			w = k;
			break;
		}
	}

	template<typename TexColor>
	HRESULT renderSlicesToVolumeTexture(ID3D11DeviceContext* pContext,
		std::vector<ID3D11Texture2D*>& texSlices, ViewDirType vdt, UINT mipLevel, 
		ID3D11Texture3D* tex3d)
	{
		if (texSlices.empty())
			return S_FALSE;

		HRESULT hr;
		D3D11_MAPPED_SUBRESOURCE mapped3dTex;  
		D3D11_MAPPED_SUBRESOURCE mappedSlice;  

		V_RETURN(pContext->Map(tex3d, mipLevel, D3D11_MAP_WRITE, 0, &mapped3dTex));

		D3D11_TEXTURE2D_DESC tex2dDesc;
		texSlices.front()->GetDesc(&tex2dDesc);
		UINT width2d = tex2dDesc.Width;
		UINT height2d = tex2dDesc.Height;

		D3D11_TEXTURE3D_DESC tex3dDesc;
		tex3d->GetDesc(&tex3dDesc);
		UINT width3d = tex3dDesc.Width >> mipLevel;
		UINT height3d = tex3dDesc.Height >> mipLevel;
		UINT depth3d = tex3dDesc.Depth >> mipLevel;

		TexColor* dstTexClr = (TexColor*)mapped3dTex.pData;
		UINT rowSize3d = mapped3dTex.RowPitch / sizeof(TexColor);
		UINT slizeSize3d = mapped3dTex.DepthPitch / sizeof(TexColor);
		UINT u,v,w;

		for (UINT k = 0; k < texSlices.size(); ++k)
		{
			if(pContext->Map(texSlices[k], 0, D3D11_MAP_READ, 0, &mappedSlice) == S_OK)
			{
				UINT rowSize2d = mappedSlice.RowPitch / sizeof(TexColor);
				TexColor* srcTexClr = (TexColor*)mappedSlice.pData;
				for (UINT i = 0; i < height2d; ++i)
				{
					for (UINT j = 0; j < width2d; ++j)
					{
						getUVW(i, j, k, vdt, width3d, height3d, depth3d, u, v, w);
						TexColor srcClr = srcTexClr[i*rowSize2d + j];
						TexColor dstClr = dstTexClr[w*slizeSize3d + v*rowSize3d + u];
						dstTexClr[w*slizeSize3d + v*rowSize3d + u] = TexColor::getResColor(srcClr, dstClr);
					}
				}
				pContext->Unmap(texSlices[k], 0);	
			}
		}

		pContext->Unmap(tex3d, 0);

		return S_OK;
	}
}

TextureRenderer::TextureRenderer()
:_pd3dDevice(0), _tex3d(0), 
_pEffect(0), _pMeshVertexLayout(0), _pTextureVertexLayout(0), 
_pMeshDrawTechnique(0), _pTextureDrawTechnique(0),
_pMeshNormDrawTechnique(0), _pTextureNormDrawTechnique(0),
_ptxDiffuseVariable(0), _pAmbient(0), _pOpacity(0),
_pWorldViewProjection(0), _pLayer(0)
{
}

TextureRenderer::~TextureRenderer()
{
	release();
}

void TextureRenderer::release()
{
	SAFE_RELEASE(_pTextureVertexLayout);
	SAFE_RELEASE(_pMeshVertexLayout);
	SAFE_RELEASE(_pTexVertextBuffer);
	SAFE_RELEASE(_pEffect);
}

HRESULT TextureRenderer::init(ID3D11Device* pd3dDevice)
{
	_pd3dDevice = pd3dDevice;

	HRESULT hr;
	// Read the D3DX effect file
	D3D10_SHADER_MACRO effectMacros[2];
	effectMacros[0].Definition = "8";
	effectMacros[0].Name = "MSAA_SAMPLES_COUNT";
	effectMacros[1].Definition = 0;
	effectMacros[1].Name = 0;

	ID3D10Blob *effectBlob = NULL;
	ID3D10Blob *errorBlob = NULL;
	while (FAILED(D3DX11CompileFromFile(L"RenderTexture.fx", effectMacros, NULL, NULL, "fx_5_0", NULL, NULL, NULL, 
		&effectBlob, &errorBlob, NULL)))
	{
		DXUTOutputDebugStringA((char*)errorBlob->GetBufferPointer());
		if (MessageBoxA(0, (char*)errorBlob->GetBufferPointer(), "Failed to compile shader", MB_RETRYCANCEL) == IDCANCEL)
			return hr;
	}

	V( D3DX11CreateEffectFromMemory(effectBlob->GetBufferPointer(), effectBlob->GetBufferSize(), 0, pd3dDevice, &_pEffect) );

	SAFE_RELEASE(effectBlob);
	SAFE_RELEASE(errorBlob);

	// Obtain the technique
	_pMeshDrawTechnique = _pEffect->GetTechniqueByName( "TexturedMesh" );
	_pTextureDrawTechnique = _pEffect->GetTechniqueByName( "RenderTextureQuad" );
	_pMeshNormDrawTechnique = _pEffect->GetTechniqueByName( "RenderMeshNormals" );
	_pTextureNormDrawTechnique = _pEffect->GetTechniqueByName( "RenderNormTextureQuad" );
	_ptxDiffuseVariable = _pEffect->GetVariableByName( "g_MeshTexture" )->AsShaderResource();    
	_ptxMSAATexVariable = _pEffect->GetVariableByName( "g_MSAATexture" )->AsShaderResource();    

	_pAmbient = _pEffect->GetVariableByName( "g_vMaterialAmbient" )->AsVector();
	_pOpacity = _pEffect->GetVariableByName( "g_fMaterialAlpha" )->AsScalar();
	_pWorldViewProjection = _pEffect->GetVariableByName( "g_mWorldViewProjection" )->AsMatrix();
	_pLayer = _pEffect->GetVariableByName( "g_uiLayer" )->AsScalar();

	{
		// Define the mesh input layout
		const D3D11_INPUT_ELEMENT_DESC meshLayout[] =
		{
			{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
			{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
			{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		} ;
		UINT numElements = sizeof( meshLayout ) / sizeof( meshLayout[0] );
		D3DX11_PASS_DESC PassDesc;
		_pMeshDrawTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
		V_RETURN( pd3dDevice->CreateInputLayout( meshLayout, numElements, PassDesc.pIAInputSignature,
			PassDesc.IAInputSignatureSize, &_pMeshVertexLayout ) );
	}

	{
		// Define the texture input layout
		const D3D11_INPUT_ELEMENT_DESC texLayout[] =
		{
			{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
			{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		} ;
		UINT numElements = sizeof( texLayout ) / sizeof( texLayout[0] );

		// Create the input layout
		D3DX11_PASS_DESC PassDesc;
		_pTextureDrawTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
		V_RETURN( pd3dDevice->CreateInputLayout( texLayout, numElements, PassDesc.pIAInputSignature,
			PassDesc.IAInputSignatureSize, &_pTextureVertexLayout) );
	}

	createTexVertexBuffer();

	return S_OK;
}

HRESULT	TextureRenderer::createTexVertexBuffer()
{
	HRESULT hr;

	std::vector<TEXVERTEX> vertices(4);
	vertices[0].pos = D3DXVECTOR3(-1,-1,0);
	vertices[0].tex = D3DXVECTOR2(0, 1);

	vertices[1].pos = D3DXVECTOR3(1,-1,0);
	vertices[1].tex = D3DXVECTOR2(1, 1);

	vertices[2].pos = D3DXVECTOR3(-1,1,0);
	vertices[2].tex = D3DXVECTOR2(0, 0);

	vertices[3].pos = D3DXVECTOR3(1,1,0);
	vertices[3].tex = D3DXVECTOR2(1, 0);

	{
		D3D11_BUFFER_DESC bufferDesc;
		bufferDesc.ByteWidth = ( UINT ) sizeof(TEXVERTEX)*vertices.size();
		bufferDesc.Usage = D3D11_USAGE_DEFAULT;
		bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		bufferDesc.CPUAccessFlags = 0;
		bufferDesc.MiscFlags = 0;

		D3D11_SUBRESOURCE_DATA initData;
		initData.pSysMem = &(*vertices.begin());
		initData.SysMemPitch = 0;
		initData.SysMemSlicePitch = 0;

		V_RETURN ( _pd3dDevice->CreateBuffer( &bufferDesc, &initData, &_pTexVertextBuffer) );
	}

	return S_OK;
}

HRESULT TextureRenderer::render(const WCHAR* meshPath, const WCHAR* texPath, const WCHAR* texNormPath, UINT texHeight)
{
	ID3D11DeviceContext* pContext = DXUTGetD3D11DeviceContext();
	HRESULT hr;

	UINT lastViewPortsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
	D3D11_VIEWPORT *lastViewports = new D3D11_VIEWPORT[lastViewPortsCount];
	pContext->RSGetViewports(&lastViewPortsCount, lastViewports);

	V_RETURN( _mesh.load( _pd3dDevice, meshPath ) );
	_mesh.loadTextures(pContext);

	textureFormat = DXGI_FORMAT_R16G16B16A16_UNORM; 
	if ((hr = renderData(texPath, texHeight, false)) != S_OK)
		return hr;

	textureFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
	if ((hr = renderData(texNormPath, texHeight, true)) != S_OK)
		return hr;

	_mesh.destroy();
	pContext->RSSetViewports(lastViewPortsCount, lastViewports);
	delete [] lastViewports;

	return S_OK;
}

HRESULT TextureRenderer::renderData(const WCHAR* texPath, UINT texHeight, bool renderNormalsMode)
{
	ID3D11DeviceContext* pContext = DXUTGetD3D11DeviceContext();
	HRESULT hr;

	const BBOX& box = _mesh.getBoundingBox();

	float texZoomC = (float)texHeight/box.dy();
	UINT texDepth = ceil(box.dz()*texZoomC);
	UINT texWidth = ceil(box.dx()*texZoomC);
	createVolumeTexture(texWidth, texHeight, texDepth, vtCPUUsage, _tex3d);

	D3D11_TEXTURE3D_DESC tex3dDesc; 
	_tex3d->GetDesc(&tex3dDesc);

	D3DXMATRIXA16 mView;
	D3DXVECTOR3 eye, lookAt, up;

	for (UINT mipLevel = 0; mipLevel < tex3dDesc.MipLevels; ++mipLevel)
	{
		{
			eye = D3DXVECTOR3(box.min.x + box.dx()*0.5f, box.min.y, box.min.z + box.dz()*0.5f);
			lookAt = D3DXVECTOR3(eye.x, box.max.y + 1.f, eye.z);
			up = D3DXVECTOR3(0, 0, -1);
			D3DXMatrixLookAtLH( &mView, &eye, &lookAt, &up );
			renderVolumeTexture(pContext, texWidth, texHeight, texDepth, mipLevel, 1.f/texZoomC, mView, vdY, renderNormalsMode, _tex3d);
		}

		{
			eye = D3DXVECTOR3(box.min.x, box.min.y + box.dy()*0.5f, box.min.z + box.dz()*0.5f);
			lookAt = D3DXVECTOR3(box.max.x + 1.f, eye.y, eye.z);
			up = D3DXVECTOR3(0, 1, 0);
			D3DXMatrixLookAtLH( &mView, &eye, &lookAt, &up );
			renderVolumeTexture(pContext, texWidth, texHeight, texDepth, mipLevel, 1.f/texZoomC, mView, vdX, renderNormalsMode, _tex3d);
		}

		{
			eye = D3DXVECTOR3(box.min.x + box.dx()*0.5f, box.min.y + box.dy()*0.5f, box.min.z);
			lookAt = D3DXVECTOR3(eye.x, eye.y, box.max.z + 1.f);
			up = D3DXVECTOR3(0, 1, 0);
			D3DXMatrixLookAtLH( &mView, &eye, &lookAt, &up );
			renderVolumeTexture(pContext, texWidth, texHeight, texDepth, mipLevel, 1.f/texZoomC, mView, vdZ, renderNormalsMode, _tex3d);
		}
	}

	V_RETURN(D3DX11SaveTextureToFile(pContext, _tex3d, D3DX11_IFF_DDS, texPath));

	
	SAFE_RELEASE(_tex3d);
	return S_OK;
}

void TextureRenderer::renderSubset( UINT iSubset, ID3D11DeviceContext* pContext, ID3DX11EffectTechnique* technique )
{
	HRESULT hr;

	const Subset& s = _mesh.getSubset(iSubset);
	Material* pMaterial = _mesh.getMaterial(s.materialId);

	V( _pAmbient->SetFloatVector( pMaterial->vAmbient ) );
	V( _pOpacity->SetFloat( pMaterial->fAlpha ) );

	if ( !IsErrorResource( pMaterial->pTexture ) )
		_ptxDiffuseVariable->SetResource( pMaterial->pTexture );

	D3DX11_TECHNIQUE_DESC techDesc;
	technique->GetDesc( &techDesc );

	pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	for ( UINT p = 0; p < techDesc.Passes; ++p )
	{
		technique->GetPassByIndex(p)->Apply(0, pContext);
		pContext->DrawIndexed(s.indCount, s.startInd, 0);
	}
}

HRESULT TextureRenderer::renderVolumeTexture(ID3D11DeviceContext* pContext, 
											 UINT texWidth, UINT texHeight, UINT texDepth, UINT mipLevel,
											 float step, const D3DXMATRIXA16& mView, 
											 ViewDirType vdt, bool renderNormalsMode,
											 ID3D11Texture3D* tex3d)
{
	ID3DX11EffectTechnique* renderMeshTech = 0, *renderQuadTech = 0;
	if (renderNormalsMode)
	{
		renderMeshTech = _pMeshNormDrawTechnique;
		renderQuadTech = _pTextureNormDrawTechnique;
	}
	else
	{
		renderMeshTech = _pMeshDrawTechnique;
		renderQuadTech = _pTextureDrawTechnique;
	}

	const BBOX& box = _mesh.getBoundingBox();
	TexSlicesData slicesData;
	UINT width2d = 0, height2d = 0, layers = 0;
	float objW = 0.f, objH = 0.f;
	switch (vdt)
	{
	case vdX:
		width2d = texDepth >> mipLevel;
		height2d = texHeight >> mipLevel;
		layers = texWidth >> mipLevel;
		objW = box.dz();
		objH = box.dy();
		break;
	case vdY:
		width2d = texWidth >> mipLevel;
		height2d = texDepth >> mipLevel;
		layers = texHeight >> mipLevel;
		objW = box.dx();
		objH = box.dz();
		break;
	case vdZ:
		width2d = texWidth >> mipLevel;
		height2d = texHeight >> mipLevel;
		layers = texDepth >> mipLevel;
		objW = box.dx();
		objH = box.dy();
		break;
	}

	UINT stepC = 1 << mipLevel;
	step *= stepC;

	HRESULT hr;
	V_RETURN(createTextureSlices(width2d, height2d, layers, slicesData));

	// Render the mesh
	ID3D11RenderTargetView* rtViewsMSAA[1];
	rtViewsMSAA[0] = slicesData.texSliceMSAARTV;

	UINT meshStrides[1] = {( UINT ) sizeof(VERTEX)};
	ID3D11Buffer* pMeshVB[1];
	pMeshVB[0] = _mesh.getVertextBuffer();

	//Render slice
	ID3D11RenderTargetView* rtViewsTex[1];
	rtViewsTex[0] = slicesData.texSliceRTV;

	UINT texStrides[1] = {( UINT ) sizeof(TEXVERTEX)};
	ID3D11Buffer* pTexVB[1];
	pTexVB[0] = _pTexVertextBuffer;

	UINT offsets[1] = {0};

	D3D11_VIEWPORT viewports[1];
	viewports[0].Height = height2d;
	viewports[0].Width = width2d;
	viewports[0].TopLeftX = 0;
	viewports[0].TopLeftY = 0;
	viewports[0].MinDepth = 0;
	viewports[0].MaxDepth = 1;

	pContext->RSSetViewports(1, viewports);

	D3DXMATRIXA16 mProj, mWorldViewProjection;

	const float clearColor[4] = { 0.f, 0.f, 0.f, 0.f };

	for (unsigned int layer = 0; layer < layers; ++layer) 
	{
		{
			pContext->OMSetRenderTargets(1, rtViewsMSAA, 0);
			pContext->ClearRenderTargetView(slicesData.texSliceMSAARTV, clearColor);
			pContext->IASetInputLayout( _pMeshVertexLayout);
			pContext->IASetVertexBuffers(0, 1, pMeshVB, meshStrides, offsets);
			pContext->IASetIndexBuffer(_mesh.getIndexBuffer(), DXGI_FORMAT_R32_UINT, 0);

			D3DXMatrixOrthoLH(&mProj, objW, objH, layer*step, (layer + 1)*step);
			mWorldViewProjection = mView * mProj;
			V( _pWorldViewProjection->SetMatrix( (float*)&mWorldViewProjection ) );

			for ( UINT iSubset = 0; iSubset < _mesh.getSubsetsCount(); ++iSubset )
				renderSubset( iSubset, pContext, renderMeshTech);
		}

		{
			pContext->OMSetRenderTargets(1, rtViewsTex, 0);
			pContext->ClearRenderTargetView(slicesData.texSliceRTV, clearColor);
			pContext->IASetInputLayout( _pTextureVertexLayout);
			pContext->IASetVertexBuffers(0, 1, pTexVB, texStrides, offsets);
			pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

			_ptxMSAATexVariable->SetResource(slicesData.texSliceMSAASRV);

			renderQuadTech->GetPassByIndex(0)->Apply(0, pContext);
			pContext->Draw(4, 0);
		}

		pContext->CopyResource(slicesData.texSlices[layer], slicesData.texSlice);
//		V(D3DX11SaveTextureToFile(pContext, slicesData.texSlices[layer], D3DX11_IFF_DDS, L"./Media/3dTex/testSlice.dds"));
	}

	return renderNormalsMode ? renderSlicesToVolumeTexture<TEXNORM>(pContext, slicesData.texSlices, vdt, mipLevel, tex3d) : renderSlicesToVolumeTexture<TEXCOLOR>(pContext, slicesData.texSlices, vdt, mipLevel, tex3d);
}
